from bisect import bisect, insort
from socket import inet_aton
from struct import unpack

def iptolong(ip):
    return unpack('!L', inet_aton(ip))[0]
        
class IPFilter:
    def __init__(self):
        self.blocked = []
        
    def add(self, start, end = None):
        if not end:
            end = start
        start = iptolong(start)
        end = iptolong(end)        
        self._add(start, end)

    def remove(self, start, end = None):
        if not end:
            end = start
        start = iptolong(start)
        end = iptolong(end)
        self.blocked.remove((start, end))

    def clear(self):
        self.blocked = []
        
    def __repr__(self):
        return repr(self.blocked)
    
    def __nonzero__(self):
        return len(self.blocked) > 0
    
    def __len__(self):
        return len(self.blocked)

    def __contains__(self, ip):
        if not self.blocked:
            return False
        ip = iptolong(ip)
        pos = bisect(self.blocked, (ip, 0))
        # Check if here
        start, end = self.blocked[pos-1]
        if start <= ip <= end: 
            return True
        # Check for the case that ip is exactly the start value
        if pos < len(self.blocked):
            start, end = self.blocked[pos]
            if start <= ip <= end: 
                return True
        return False

    def readfile(self, filename):
        try:
            self._readfile(filename)
        except:
            return False
        return True
        
    def _readfile(self, filename):
        # Read file
        f = open(filename, 'r')
        lines = f.readlines()
        f.close()
        # Analize file
        for line in lines:
            line = line.strip()
            if not line or line[0] == '#':
                continue
            line = line.split(':')[-1]
            try:
                ip1,ip2 = line.split('-')
            except:
                ip1 = line
                ip2 = line
            ip1 = iptolong(ip1)
            ip2 = iptolong(ip2)
            assert ip1 <= ip2
            self._add(ip1, ip2)
            
    def _add(self, start, end = None):
        if not end:
            end = start       
        l = self.blocked
        p = bisect(l, (start, end))-1
        if p >= 0:
            while p < len(l):
                range_beg = l[p][0]
                if range_beg > end+1:
                    done = True
                    break
                range_end = l[p][1]
                if range_end < start-1:
                    p += 1
                    if p == len(l):
                        done = True
                        break
                    continue
                # if neither of the above conditions is true, the ranges overlap
                start = min(start, range_beg)
                end = max(end, range_end)
                del l[p]
                break
        l.insert(p+1, (start, end))

try:
    import psyco
    psyco.bind(IPFilter._readfile)
except ImportError:
    pass

if __name__ == "__main__":
    from time import clock
    filter = IPFilter()
    print "Reading file"
    start = clock()
    filter.readfile("level2.txt")
    filter.readfile("level1.txt")
    print clock() - start
    print "Length:", len(filter)
    raw_input("...")

